#include <linux/init.h>
#include <linux/kobject.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/rwlock.h>
#include <linux/delay.h>

static DEFINE_RWLOCK(foo_rwlock);
static rwlock_t baz_rwlock;
static int foo = 5;
static int baz = 5;

#define COUNT_PRINT 1

static ssize_t foo_show(struct kobject* kobj, struct kobj_attribute* attr, char* buf)
{
    int ret = 0;

    pr_info("foo read lock --\n");
    read_lock(&foo_rwlock);
    ret = sysfs_emit(buf, "%d\n", foo);
    // 模拟 处理事件/延迟
    msleep(5 * 1000);

    read_unlock(&foo_rwlock);
    pr_info(" foo read unlock -- release\n");
    return ret;
}

static ssize_t foo_store(struct kobject* kobj, struct kobj_attribute* attr, const char* buf,
    size_t count)
{
    int ret;

    pr_info("foo write lock ++\n");
    write_lock(&foo_rwlock);
    ret = kstrtoint(buf, 10, &foo);

    if (ret < 0)
        return ret;
    // 模拟 处理事件/延迟
    msleep(5 * 1000);

    write_unlock(&foo_rwlock);
    pr_info("foo write unlock ++ release\n");

    return count;
}

static ssize_t baz_show(struct kobject* kobj, struct kobj_attribute* attr, char* buf)
{
    int ret;

    read_lock(&baz_rwlock);
    ret = sysfs_emit(buf, "%d\n", baz);
    // 模拟 处理事件/延迟
    {
        int count = baz;
        if (baz > 10)
            count = 10;
        while (count--) {
            msleep(1000);
            pr_info("baz read lock ing --, count=%d\n", count);
        }
    }
    read_unlock(&baz_rwlock);

    return ret;
}

static ssize_t baz_store(struct kobject* kobj, struct kobj_attribute* attr, const char* buf,
    size_t count)
{
    int ret;

    write_lock(&baz_rwlock);
    ret = kstrtoint(buf, 10, &baz);
    if (ret < 0)
        return ret;
    // 模拟 处理事件/延迟
    {
        int count = baz;
        if (baz > 10)
            count = 10;
        while (count--) {
            msleep(1000);
            pr_info("baz write lock ing ++, count=%d\n", count);
        }
    }
    write_unlock(&baz_rwlock);

    return count;
}

static struct kobj_attribute foo_attribute = __ATTR(foo, 0664, foo_show, foo_store);
static struct kobj_attribute baz_attribute = __ATTR(baz, 0664, baz_show, baz_store);

static struct attribute* attrs[] = {
    &foo_attribute.attr,
    &baz_attribute.attr,
    NULL,
};

static struct attribute_group attr_group = {
    .attrs = attrs,
};

static struct kobject* example_kobj;

static int __init example_init(void)
{
    int retval;
    example_kobj = kobject_create_and_add("kobject_example", kernel_kobj);
    if (!example_kobj)
        return -ENOMEM;
    pr_info("create sysfs: /sys/kernel/kobject_example\n");

    /* Create the files associated with this kobject */
    retval = sysfs_create_group(example_kobj, &attr_group);
    if (retval)
        kobject_put(example_kobj);

    rwlock_init(&baz_rwlock);

    return retval;
}

static void __exit example_exit(void)
{
    kobject_put(example_kobj);
}

module_init(example_init);
module_exit(example_exit);

MODULE_DESCRIPTION("sysfs and rwlock test");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("liuJiang <1637664504@qq.com>");


/* 读测试
终端1: cat /sys/kernel/kobject_example/foo
终端2: cat /sys/kernel/kobject_example/foo

Dec 30 00:12:16 ubuntu kernel: [ 4841.893369] foo read lock --
Dec 30 00:12:16 ubuntu kernel: [ 4842.720707] foo read lock --
Dec 30 00:12:21 ubuntu kernel: [ 4847.152935]  foo read unlock -- release
Dec 30 00:12:22 ubuntu kernel: [ 4847.920852]  foo read unlock -- release

结论: 读不阻塞 
*/

/* 写测试
终端1: echo 12 > /sys/kernel/kobject_example/foo
终端2: echo 15 > /sys/kernel/kobject_example/foo

kernel日志
Dec 30 00:10:05 ubuntu kernel: [ 4710.982518] foo write lock ++
Dec 30 00:10:06 ubuntu kernel: [ 4711.957103] foo write lock ++
Dec 30 00:10:10 ubuntu kernel: [ 4716.083466] foo write unlock ++ release
Dec 30 00:10:15 ubuntu kernel: [ 4721.203549] foo write unlock ++ release

结论: 写阻塞
 */